#include "pthread.h"
#include "stdio.h"
#include "string.h"
#include "input.h"
#include "debug.h"
#include "unistd.h"
#include "time.h"
#include "signal.h"

#define CLEAR_STREAM            0x00010000      

struct sensor_pkg
{
    char name[16];
    
    int data[4];
};

static int lora;
static int oled;
static pthread_t tid_se;

static int display(int fildes, const char *str, int where)
{
    lock(fildes, where, 0);
    lseek(fildes, where, SEEK_SET);
    write(fildes, str, SEEK_SET);
    unlock(fildes, where, 0);
    
    return 0;
}

static int clear(int fildes)
{
    lock(fildes, 0, 0);
    ioctl(oled, CLEAR_STREAM);  
    unlock(fildes, 0, 0);
    
    return 0;
}

static void* key_entry(void *p)
{
    struct input_event input_event;
    union sigval sigval;

access_oled:
    oled = access("/dev/oled", O_RDWR);
    if (!oled)
    {
        sleep(5);
        goto access_oled;
    }
  
    while(1)
    {     
        if (input_event_catch(INPUT_KEY_FALLING_EDGE_EVENT, &input_event, 0) > 0)
        {
            sigval.sival_int = input_event.value;
            sigqueue(tid_se, 1, sigval);
        }
    }
}

static void* lora_entry(void *p)
{
    char buffer[32];
    
access_lora:
    lora = access("/dev/lora", O_RDWR);
    if (!lora)
    {
        sleep(5);
        goto access_lora;
    }
  
    while(1)
    {
        if (read(lora, buffer, 32) > 0)
        {
            printf("lora recv is [%s].\r\n", buffer);
            display(oled, buffer, 2);
            memset(buffer, 0, sizeof(buffer));
        }
    }
}

static void key_signal(union sigval sigval)
{
    const char *log = "key:[%d]";
    int bytes;
    char buffer[32];
  
    printf("key [%d] inpressed.\r\n", sigval.sival_int + 1);
    bytes = sprintf(buffer, log, sigval.sival_int + 1);
    if (lora <= 0)
    {
        display(oled, "No lora", 2);
    }
    else if (write(lora, buffer, bytes) < 0)
    {
        printf("lora send timeout.\r\n");
        display(oled, "Time Out", 2);
    }
}

static void* sensor_entry(void *p)
{
    struct sensor_pkg sensor_pkg;
    int sensor;
    char buffer[32];
    struct tm time;
    
    signal(1, key_signal);
    
start_sensor: 
    sleep(1);
  
    memset(&sensor_pkg, 0, sizeof(struct sensor_pkg));
    sensor = -1;
    
    if ((sensor = access("/dev/sensor", O_NONBLOCK | O_RDWR)) <= 0)
    {
        printf("no sensor scanned.\r\n");
        clear(oled);
        display(oled, "No sensor", 2);
        
        goto close_sensor; 
    }
  
    while(1)
    {
        if (read(sensor, &sensor_pkg, sizeof(struct sensor_pkg)) > 0)
        {
            clear(oled);
          
            display(oled, sensor_pkg.name, 2);
            
            localtime_r(NULL, &time);
            
            sprintf(buffer, "time: %02u:%02u:%02u", time.tm_hour, time.tm_min, time.tm_sec);
            display(oled, buffer, 2 + 16);
            
            if (!strcmp(sensor_pkg.name, "sht10"))
            {
                sprintf(buffer, "temp: %u.%u", sensor_pkg.data[1] / 100, sensor_pkg.data[1] % 100);
                display(oled, buffer, 2 + 32);
            
                sprintf(buffer, "humi: %u.%u%", sensor_pkg.data[2] / 100, sensor_pkg.data[2] % 100);
                display(oled, buffer, 2 + 48);
            }
            else if (!strcmp(sensor_pkg.name, "accel"))
            {
                sprintf(buffer, "xyz: %d.%d.%d", sensor_pkg.data[0], sensor_pkg.data[1], sensor_pkg.data[2]);
                display(oled, buffer, 2 + 32);               
            }
            else if (!strcmp(sensor_pkg.name, "pressure"))
            {
                sprintf(buffer, "val: %d Pa", sensor_pkg.data[0]);
                display(oled, buffer, 2 + 32);               
            }
            else if (!strcmp(sensor_pkg.name, "hall"))
            {
                sprintf(buffer, "val: %d", sensor_pkg.data[0]);
                display(oled, buffer, 2 + 32);               
            }
            else if (!strcmp(sensor_pkg.name, "rain"))
            {
                sprintf(buffer, "val: %d", sensor_pkg.data[0]);
                display(oled, buffer, 2 + 32);               
            }
            else if (!strcmp(sensor_pkg.name, "shock"))
            {
                sprintf(buffer, "val: %d", sensor_pkg.data[0]);
                display(oled, buffer, 2 + 32);               
            }
            else if (!strcmp(sensor_pkg.name, "alcohol"))
            {
                sprintf(buffer, "val: %d", sensor_pkg.data[0]);
                display(oled, buffer, 2 + 32);               
            }
            else
            {
                sprintf(buffer, "no scan");
                display(oled, buffer, 2 + 32);
            }
        }
        else
        {
            clear(oled);
            sprintf(buffer, "error");
            display(oled, buffer, 2);
            
            goto close_sensor;
        }
        
        sleep(1);
    }
    
close_sensor:
    close(sensor);
    goto start_sensor;
}

err_t app_init(void)
{
    int err;
    pthread_t tid;

    err = pthread_create(&tid, NULL, key_entry, NULL);
    ASSERT_KERNEL(!err);
    pthread_setname_np(tid, "apkey");

    err = pthread_create(&tid, NULL, lora_entry, NULL);
    ASSERT_KERNEL(!err);
    pthread_setname_np(tid, "aplora");
    
    err = pthread_create(&tid_se, NULL, sensor_entry, NULL);
    ASSERT_KERNEL(!err);
    pthread_setname_np(tid, "apsensor");
  
    return 0;
}
